package com.instalinks.android.lib;

import java.text.DecimalFormat;
import java.util.ArrayList;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;

import com.instalinks.android.lib.enums.DeviceType;
import com.instalinks.android.lib.enums.NetworkType;

public class PhoneAttributes {

	private final Context context;

	public String primaryEmail = "";
	public String deviceId = "";
	public String subscriberId = "";
	public String batteryStatus = "";
	public String signalStrength = "";
	public String location = "";
	public boolean isConnected = false;
	public NetworkType networkType = NetworkType.UnknownNotConnected;
	public DeviceType deviceType = DeviceType.Unknown;

	private String sSignalStrength = "UNK";

	private PhoneStateListener listener;

	public PhoneAttributes(Context context) {
		this.context = context;
		listener = new MyDeviceStateListner();
		resetAllAttributes();
	}

	private class MyDeviceStateListner extends PhoneStateListener {
		@Override
		public void onSignalStrengthsChanged(SignalStrength signalStrength) {
			super.onSignalStrengthsChanged(signalStrength);

			sSignalStrength = String.valueOf(signalStrength
					.getGsmSignalStrength());
		}
	}

	public void resetAllAttributes() {
		primaryEmail = getPrimaryAccount();
		deviceId = getDeviceId();
		subscriberId = getSubscriberId();
		batteryStatus = getBatteryStatus();
		signalStrength = getSignalStrength();
		location = getLocation().toString();
		isConnected = isConnectedToNetwork();
		networkType = getNetworkType();
		deviceType = getDeviceType();

	}

	/**
	 * Gets the list of all registered Google related accounts from your device
	 * 
	 * @param context
	 * @return
	 */
	protected ArrayList<String> getRegisteredGoogleAccounts() {

		ArrayList<String> acc = new ArrayList<String>();
		try {
			AccountManager aMgr = AccountManager.get(context);

			Account[] accounts = aMgr.getAccountsByType("com.google");

			for (Account a : accounts) {
				acc.add(a.name);
			}
		} catch (Exception e) {
			Log.e("[ANDROID_LIB]", e.getMessage());
		}

		return acc;
	}

	protected String getPrimaryAccount() {
		try {
			AccountManager aMgr = AccountManager.get(context);

			Account[] accounts = aMgr.getAccountsByType("com.google");

			if (accounts.length > 0)
				return accounts[0].name;
		} catch (Exception e) {
			Log.e("[ANDROID_LIB]", e.getMessage());
		}
		return "";
	}

	protected String getSubscriberId() {
		try {
			TelephonyManager tm = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			return tm.getSubscriberId();
		} catch (Exception e) {
			return "";
		}
	}

	protected String getDeviceId() {
		try {
			TelephonyManager tm = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			return tm.getDeviceId();
		} catch (Exception e) {
			return "";
		}
	}

	protected DeviceType getDeviceType() {
		try {
			TelephonyManager tm = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			switch (tm.getPhoneType()) {
			case TelephonyManager.PHONE_TYPE_CDMA:
				return DeviceType.CDMA;
			case TelephonyManager.PHONE_TYPE_GSM:
				return DeviceType.GSM;
			default:
				return DeviceType.Unknown;
			}
		} catch (Exception e) {
			return DeviceType.Unknown;
		}

	}

	protected boolean isConnectedToNetwork() {
		try {
			ConnectivityManager connectivity = (ConnectivityManager) context
					.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo info = connectivity.getActiveNetworkInfo();
			if (info == null) {
				return false;
			}
			if (info.getState() == NetworkInfo.State.CONNECTED)
				return true;

			return false;
		} catch (Exception ex) {
			return false;
		}
	}

	protected String getBatteryStatus() {
		try {
			Intent batteryIntent = context.registerReceiver(null,
					new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
			int rawlevel = batteryIntent.getIntExtra("level", -1);

			double scale = batteryIntent.getIntExtra("scale", -1);
			double level = -1;
			if (rawlevel >= 0 && scale > 0) {
				level = 100 * rawlevel / scale;

				DecimalFormat df = new DecimalFormat("##.##");
				return String.valueOf(df.format(level)) + "%";
			}
		} catch (Exception e) {
			return "UNK";
		}
		return "UNK";
	}

	protected String getSignalStrength() {
		try {
			TelephonyManager mgr = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			mgr.listen(listener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);

			return sSignalStrength;
		} catch (Exception e) {
			return "";
		}
	}

	protected NetworkType getNetworkType() {
		try {
			ConnectivityManager connectivity = (ConnectivityManager) context
					.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo info = connectivity.getActiveNetworkInfo();
			if (info == null) {
				return NetworkType.UnknownNotConnected;
			} else {
				int netType = info.getType();
				int netSubType = info.getSubtype();

				if (netType == ConnectivityManager.TYPE_WIFI) {
					return NetworkType.WiFi;
				} else if (netType == ConnectivityManager.TYPE_WIMAX) {
					return NetworkType.WiMax;
				} else if (netType == ConnectivityManager.TYPE_MOBILE) {
					if (netSubType == TelephonyManager.NETWORK_TYPE_EDGE)
						return NetworkType.EDGE;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_GPRS)
						return NetworkType.GPRS;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_HSDPA)
						return NetworkType.HSDPA;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_UMTS)
						return NetworkType.UMTS;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_1xRTT)
						return NetworkType.xRTT;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_IDEN)
						return NetworkType.IDEN;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_HSPA)
						return NetworkType.HSPA;
					else if (netSubType == TelephonyManager.NETWORK_TYPE_HSUPA)
						return NetworkType.HSUPA;
					else
						return NetworkType.UnknownConnected;
				} else if (netType == ConnectivityManager.TYPE_MOBILE_DUN) {
					return NetworkType.DUN;
				} else if (netType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
					return NetworkType.HIPRI;
				} else if (netType == ConnectivityManager.TYPE_MOBILE_MMS) {
					return NetworkType.MMS;
				} else if (netType == ConnectivityManager.TYPE_MOBILE_SUPL) {
					return NetworkType.SUPL;
				} else {
					return NetworkType.UnknownConnected;
				}
			}

		} catch (Exception ex) {
			return NetworkType.UnknownNotConnected;
		}
	}

	protected DeviceLocation getLocation() {
		DeviceLocation deviceLocation = new DeviceLocation(0, 0);
		int cid = 0;
		int lac = 0;
		String mcc = "0";
		String mnc = "0";

		try {
			TelephonyManager tm = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);

			CellLocation cellLocation = tm.getCellLocation();
			if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
				cid = ((GsmCellLocation) cellLocation).getCid();
				lac = ((GsmCellLocation) cellLocation).getLac();
				mcc = tm.getNetworkOperator().substring(0, 3);
				mnc = tm.getNetworkOperator().substring(3);
			}
			return new DeviceLocation(cid, lac, mcc, mnc);
		} catch (Exception e) {
		}

		return deviceLocation;
	}

	public class DeviceLocation {
		private int _cid = 0;
		private int _lac = 0;
		private String _mcc = "0";
		private String _mnc = "0";

		public DeviceLocation(int cid, int lac) {
			this._cid = cid;
			this._lac = lac;
		}

		public DeviceLocation(int cid, int lac, String mcc, String mnc) {
			this._cid = cid;
			this._lac = lac;
			this._mcc = mcc;
			this._mnc = mnc;
		}

		public float getCID() {
			return this._cid;
		}

		public float getLAC() {
			return this._lac;
		}

		public String getMCC() {
			return this._mcc;
		}

		public String getMNC() {
			return this._mnc;
		}

		@Override
		public String toString() {
			return String.valueOf(_cid) + "," + String.valueOf(_lac) + ","
					+ _mcc + "," + _mnc;
		}
	}

}
